#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/delay.h>
/*驱动注册的头文件，包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
#include <linux/device.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>
/*Linux中申请GPIO的头文件*/
#include <linux/gpio.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <mach/gpio.h>




#define ldp_MAGIC 'K'
#define IOCTL_LDP_INTERLOCK_READ_1		_IOW	(ldp_MAGIC, 1, int)
#define IOCTL_LDP_INTERLOCK_READ_2		_IOW	(ldp_MAGIC, 2, int)

#define IOCTL_LDP_ENABLE_WRITE_1		_IOW	(ldp_MAGIC, 3, int)
#define IOCTL_LDP_ENABLE_WRITE_2		_IOW	(ldp_MAGIC, 4, int)

#define IOCTL_LDP_LM_FAULT_READ_1		_IOW	(ldp_MAGIC, 5, int)
#define IOCTL_LDP_LM_FAULT_READ_2		_IOW	(ldp_MAGIC, 6, int)

#define IOCTL_LDP_TEMP_FAULT_READ_1		_IOW	(ldp_MAGIC, 7, int)
#define IOCTL_LDP_TEMP_FAULT_READ_2		_IOW	(ldp_MAGIC, 8, int)

#define IOCTL_LED_WRITE					_IOW	(ldp_MAGIC, 9, int)


#define GPIO_LDP_INTERLOCK_1			NUC980_PB1
#define GPIO_LDP_INTERLOCK_2			NUC980_PD4

#define GPIO_LDP_ENABLE_1				NUC980_PB7
#define GPIO_LDP_ENABLE_2				NUC980_PD2

#define GPIO_LDP_LM_FAULT_1				NUC980_PB5
#define GPIO_LDP_LM_FAULT_2				NUC980_PD3

#define GPIO_LDP_TEMP_FAULT_1			NUC980_PB3
#define GPIO_LDP_TEMP_FAULT_2			NUC980_PD5

#define GPIO_LED						NUC980_PA0



static int major;
static struct class *jt_ldp_class;
static struct device *jt_ldp_device;


MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Dongweibo");



/*操作函数*/
static long ldp_ioctl(struct file *files, unsigned int cmd,unsigned long arg)
{
	switch(cmd)
	{
		
		case IOCTL_LDP_INTERLOCK_READ_1:	/*GPIO_LDP_INTERLOCK_1*/
			return (long)(gpio_get_value(GPIO_LDP_INTERLOCK_1));	
			break;
			
		case IOCTL_LDP_INTERLOCK_READ_2:	/*GPIO_LDP_INTERLOCK_2*/
			return (long)(gpio_get_value(GPIO_LDP_INTERLOCK_2));	
			break;
			
		case IOCTL_LDP_ENABLE_WRITE_1:		/*IOCTL_LDP_ENABLE_WRITE_1*/
			gpio_set_value(GPIO_LDP_ENABLE_1, arg);
			return 0;
			break;
			
		case IOCTL_LDP_ENABLE_WRITE_2:		/*IOCTL_LDP_ENABLE_WRITE_2*/
			gpio_set_value(GPIO_LDP_ENABLE_2, arg);
			return 0;
			break;
			
		case IOCTL_LDP_LM_FAULT_READ_1:		/*IOCTL_LDP_LM_FAULT_READ_1*/
			return (long)(gpio_get_value(GPIO_LDP_LM_FAULT_1));	
			break;
			
		case IOCTL_LDP_LM_FAULT_READ_2:		/*IOCTL_LDP_LM_FAULT_READ_2*/
			return (long)(gpio_get_value(GPIO_LDP_LM_FAULT_2));	
			break;	
			
		case IOCTL_LDP_TEMP_FAULT_READ_1:	/*IOCTL_LDP_TEMP_FAULT_READ_1*/
			return (long)(gpio_get_value(GPIO_LDP_TEMP_FAULT_1));	
			break;	
		case IOCTL_LDP_TEMP_FAULT_READ_2:	/*IOCTL_LDP_TEMP_FAULT_READ_2*/
			return (long)(gpio_get_value(GPIO_LDP_TEMP_FAULT_2));	
			break;
		case IOCTL_LED_WRITE:
			gpio_set_value(GPIO_LED, arg);
			return 0;
			break;
		default:
			return 0xff;
			break;
	}    
    return 0;
}
/*释放函数*/
static int ldp_release(struct inode *inode, struct file *file)
{
//    printk(KERN_EMERG "[M]gpio_buzzer release\n");
    return 0;
}
/*打开函数*/
static int ldp_open(struct inode *inode, struct file *file)
{
//    printk(KERN_EMERG "[M]gpio_buzzer open\n");
    return 0;
}
/*ops结构体，存储相关的操作函数*/
static struct file_operations ldp_ops = 
{
    .owner			= 	THIS_MODULE,
    .open			= 	ldp_open,
    .release		= 	ldp_release,
    .unlocked_ioctl	= 	ldp_ioctl,
};

static int ldp_ops_init(void)
{
	int ret;
	printk(KERN_EMERG "[M] module ldp init!\n");
	
	/*GPIO_LDP_INTERLOCK_1*/
	ret = gpio_request(GPIO_LDP_INTERLOCK_1,"GPIO_ldp_interlock_1");
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_interlock_1 requeset failed!\n");
	    return ret;
	}
	ret = gpio_direction_input(GPIO_LDP_INTERLOCK_1);
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_interlock_1 set input failed!\n");
	    return ret;
	}
	
	/*GPIO_LDP_INTERLOCK_2*/
	ret = gpio_request(GPIO_LDP_INTERLOCK_2,"GPIO_ldp_interlock_2");
	if(ret < 0)
	{
	  printk(KERN_EMERG "[M]GPIO_ldp_interlock_2 requeset failed!\n");
	  return ret;
	}
	ret = gpio_direction_input(GPIO_LDP_INTERLOCK_2);
	if(ret < 0)
	{
	  printk(KERN_EMERG "[M]GPIO_ldp_interlock_2 set input failed!\n");
	  return ret;
	}
	
	/*IOCTL_LDP_ENABLE_WRITE_1*/
	ret = gpio_request(GPIO_LDP_ENABLE_1,"GPIO_ldp_enable_write_1");
	if(ret < 0)
	{
	  printk(KERN_EMERG "[M]GPIO_ldp_enable_write_1 requeset failed!\n");
	  return ret;
	}
	ret = gpio_direction_output(GPIO_LDP_ENABLE_1,0);
	if(ret < 0)
	{
	  printk(KERN_EMERG "[M]GPIO_ldp_enable_write_1 set input failed!\n");
	  return ret;
	} 
	
	/*IOCTL_LDP_ENABLE_WRITE_2*/
	ret = gpio_request(GPIO_LDP_ENABLE_2,"GPIO_ldp_enable_write_2");
	if(ret < 0)
	{
	  printk(KERN_EMERG "[M]GPIO_ldp_enable_write_2 requeset failed!\n");
	  return ret;
	}
	ret = gpio_direction_output(GPIO_LDP_ENABLE_2,0);
	if(ret < 0)
	{
	  printk(KERN_EMERG "[M]GPIO_ldp_enable_write_2 set input failed!\n");
	  return ret;
	} 
	
	/*GPIO_LDP_LM_FAULT_1*/
	ret = gpio_request(GPIO_LDP_LM_FAULT_1,"GPIO_ldp_lm_fault_1");
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_lm_fault_1 requeset failed!\n");
	    return ret;
	}
	ret = gpio_direction_input(GPIO_LDP_LM_FAULT_1);
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_lm_fault_1 set input failed!\n");
		 return ret;
	} 
	
	/*GPIO_LDP_LM_FAULT_2*/
	ret = gpio_request(GPIO_LDP_LM_FAULT_2,"GPIO_ldp_lm_fault_2");
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_lm_fault_2 requeset failed!\n");
	    return ret;
	}
	ret = gpio_direction_input(GPIO_LDP_LM_FAULT_2);
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_lm_fault_2 set input failed!\n");
		return ret;
	}

	/*GPIO_LDP_TEMP_FAULT_1*/
	ret = gpio_request(GPIO_LDP_TEMP_FAULT_1,"GPIO_ldp_temp_fault_1");
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_temp_fault_1 requeset failed!\n");
	    return ret;
	}
	ret = gpio_direction_input(GPIO_LDP_TEMP_FAULT_1);
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_temp_fault_1 set input failed!\n");
		return ret;
	}

	/*GPIO_LDP_TEMP_FAULT_2*/
	ret = gpio_request(GPIO_LDP_TEMP_FAULT_2,"GPIO_ldp_temp_fault_2");
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_temp_fault_2 requeset failed!\n");
	    return ret;
	}
	ret = gpio_direction_input(GPIO_LDP_TEMP_FAULT_2);
	if(ret < 0)
	{
	    printk(KERN_EMERG "[M]GPIO_ldp_temp_fault_2 set input failed!\n");
		return ret;
	} 	
	
	/*GPIO_LED*/
	ret = gpio_request(GPIO_LED,"GPIO_led");
	if(ret < 0)
	{
		printk(KERN_EMERG "[M]GPIO_led requeset failed!\n");
		return ret;
	}
	ret = gpio_direction_output(GPIO_LED,1);
	if(ret < 0)
	{
	  printk(KERN_EMERG "[M]GPIO_led set input failed!\n");
	  return ret;
	} 
	
	/* set major */	
	major = register_chrdev(0, "ldp_gpio", &ldp_ops);  
		
	jt_ldp_class = class_create(THIS_MODULE, "ldp_gpio_class");
	if (!jt_ldp_class) 
	{
	    printk(KERN_INFO "[M]jt_ldp_class create fail\n");
	    return -1;
	}
	/* 此处的名字即为驱动中显示的名字 */
	jt_ldp_device = device_create(jt_ldp_class, NULL, MKDEV(major, 0), NULL, "ldp");
	if (!jt_ldp_device) 
	{
	    printk(KERN_INFO "[M]jt_ldp_device create fail\n");
	    return -1;
	}
	return 0;
}

static void ldp_ops_exit(void)
{
    printk(KERN_EMERG "[M]module ldp exit!\n");    
    unregister_chrdev(major,"ldp_gpio");  
	
    gpio_free(GPIO_LDP_INTERLOCK_1);
	gpio_free(GPIO_LDP_INTERLOCK_2);
	
	gpio_free(GPIO_LDP_ENABLE_1);
	gpio_free(GPIO_LDP_ENABLE_2);
	
	gpio_free(GPIO_LDP_LM_FAULT_1);
	gpio_free(GPIO_LDP_LM_FAULT_2);
	
	gpio_free(GPIO_LDP_TEMP_FAULT_1);
	gpio_free(GPIO_LDP_TEMP_FAULT_2);

    gpio_free(GPIO_LED);
	
	
    device_unregister(jt_ldp_device);
    class_destroy(jt_ldp_class);    
	
}

module_init(ldp_ops_init);
module_exit(ldp_ops_exit);



